/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-  */
/*
 * window-wrapper.c
 * Copyright (C) 2014 Weiketing <weikting@gmail.com>
 *
 * gtkapkmanager is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * gtkapkmanager is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <config.h>

#include "window-wrapper.h"
#include "gapkobject.h"
#include "adbutils.h"
#include <glib/gi18n.h>

#define UI_FILE PACKAGE_DATA_DIR"/ui/gtkapkmanager.ui"
///#define UI_FILE "src/gtkapkmanager.ui"
#define TOP_WINDOW "window"

static void
window_wrapper_update_combo(WindowWrapper *self);

struct _WindowWrapperPrivate
{
	GApplication *thisApp;
	GtkBuilder *builder;
	GtkWindow *window;
	GApkObject *apk;

	GtkWidget *app_icon;
	GtkWidget *app_label;
	GtkWidget *btn_install;
	GtkWidget *btn_cancel;
	GtkWidget *btn_refresh;
	GtkWidget *devices_box;
	GtkWidget *app_box;

	GtkListStore *device_list;
	GSList	     *adb_device_list;

	gchar *current_serial;

	gboolean kill_before_device_list;

	GtkWidget *message_dialog;
	GtkWidget *spinner;
	GtkWidget *msg_label;
	GtkWidget *btn_dialog;

	gboolean isWorking;
};

enum {
        TARGET_INT32,
        TARGET_STRING,
        TARGET_URI_LIST,
};

/* datatype (string), restrictions on DnD (GtkTargetFlags), datatype (int) */
static GtkTargetEntry target_list[] = {
        { "INTEGER",    0, TARGET_INT32 },
        { "STRING",     0, TARGET_STRING },
        { "text/plain", 0, TARGET_STRING },
        { "text/uri-list", 0, TARGET_URI_LIST},
};

static guint n_targets = G_N_ELEMENTS (target_list);

#define SETUP_OBJECT(self,n) { self->priv->n = gtk_builder_get_object (self->priv->builder,#n); }

G_DEFINE_TYPE (WindowWrapper, window_wrapper, G_TYPE_OBJECT);

static void
window_wrapper_init (WindowWrapper *window_wrapper)
{
	window_wrapper->priv = G_TYPE_INSTANCE_GET_PRIVATE (window_wrapper, WINDOW_TYPE_WRAPPER, WindowWrapperPrivate);

	window_wrapper->priv->apk = g_apk_object_new();
}

static void
window_wrapper_finalize (GObject *object)
{
	WindowWrapper *self = WINDOW_WRAPPER(object);
	g_object_unref (self->priv->builder);
	g_object_unref (self->priv->apk);
	self->priv->window = NULL;
	g_free(self->priv->current_serial);
	G_OBJECT_CLASS (window_wrapper_parent_class)->finalize (object);
}

static void
window_wrapper_class_init (WindowWrapperClass *klass)
{
	GObjectClass* object_class = G_OBJECT_CLASS (klass);

	g_type_class_add_private (klass, sizeof (WindowWrapperPrivate));

	object_class->finalize = window_wrapper_finalize;
}

static WindowWrapper* window_wrapper_new()
{
	return g_object_new (WINDOW_TYPE_WRAPPER,NULL);
}

static void window_wrapper_update_btn_install(WindowWrapper *self)
{
	GtkTreeIter iter;
	gboolean d = gtk_combo_box_get_active_iter(GTK_COMBO_BOX(self->priv->devices_box),&iter);
	gboolean f = g_apk_object_is_opened(self->priv->apk);
	gtk_widget_set_sensitive (self->priv->btn_install,f &&d);
}

static void window_wrapper_update_app(WindowWrapper *self){
	if(g_apk_object_is_opened(self->priv->apk)){
		gtk_image_set_from_pixbuf (GTK_IMAGE(self->priv->app_icon),g_apk_object_get_icon(self->priv->apk));
		gchar *dn = g_strdup_printf("%s %s",g_apk_object_appname(self->priv->apk),g_apk_object_version_name(self->priv->apk));
		gtk_label_set_label (GTK_LABEL(self->priv->app_label),dn);
		g_free(dn);
	}else{
		gtk_image_set_from_pixbuf (GTK_IMAGE(self->priv->app_icon),NULL);
		gtk_label_set_label (GTK_LABEL(self->priv->app_label),"Drag an apk file to here");
	}
}

static void
window_wrapper_on_open_result(WindowWrapper *self,const gchar *msg,gboolean isOk,GApkObject *apk)
{
	if(isOk){
		window_wrapper_update_app(self);
	}
	window_wrapper_update_btn_install(self);
}

static void
window_wrapper_init_widgets(WindowWrapper *self){

	SETUP_OBJECT(self,app_icon);
	SETUP_OBJECT(self,app_label);
	SETUP_OBJECT(self,btn_cancel);
	SETUP_OBJECT(self,btn_install);
	SETUP_OBJECT(self,btn_refresh);
	SETUP_OBJECT(self,device_list);
	SETUP_OBJECT(self,devices_box);
	SETUP_OBJECT(self,app_box);

	SETUP_OBJECT(self,message_dialog);
	SETUP_OBJECT(self,spinner);
	SETUP_OBJECT(self,msg_label);
	SETUP_OBJECT(self,btn_dialog);

	g_signal_connect_swapped(self->priv->apk,"open-result",G_CALLBACK(window_wrapper_on_open_result),self);
	gtk_drag_dest_set (self->priv->app_box,GTK_DEST_DEFAULT_ALL,target_list,n_targets,GDK_ACTION_COPY);
}


static gboolean
window_wrapper_on_load_devices_finished(WindowWrapper *self)
{
	window_wrapper_update_combo(self);
	gtk_widget_set_sensitive (self->priv->btn_refresh,TRUE);
	gtk_widget_set_sensitive (self->priv->devices_box,TRUE);
	window_wrapper_update_btn_install (self);
	return FALSE;
}

static gpointer*
window_wrapper_load_devices_thread(WindowWrapper *self)
{
	if(self->priv->kill_before_device_list){
		g_spawn_command_line_sync ("adb kill-server",NULL,NULL,NULL,NULL);
		g_usleep (G_USEC_PER_SEC);
		g_spawn_command_line_sync ("adb start-server",NULL,NULL,NULL,NULL);
		g_usleep (G_USEC_PER_SEC);
	}

	self->priv->kill_before_device_list = FALSE;
	GSList *list = adb_device_list();
	adb_device_list_free(self->priv->adb_device_list);
	self->priv->adb_device_list = list;
	g_idle_add (window_wrapper_on_load_devices_finished,self);
	return NULL;
}

static void
window_wrapper_load_devices(WindowWrapper *self)
{
	gtk_widget_set_sensitive (self->priv->devices_box,FALSE);
	g_thread_unref (g_thread_new("load",window_wrapper_load_devices_thread,self));
}

static void
window_wrapper_update_combo(WindowWrapper *self)
{
	GtkListStore *store = self->priv->device_list;
	gtk_list_store_clear (store);
	GtkTreeIter aiter;
	GtkTreeIter iter;
	GSList *l = self->priv->adb_device_list;
	while(l){
		AdbDevice *ad = l->data;
		gchar *dn = g_strdup_printf("%s %s -- Android %s",ad->brand,ad->model,ad->os_version);
		gtk_list_store_append (store,&iter);
		gtk_list_store_set (store,&iter,
							0,dn,
		                    1,ad->serial,
		                    -1);
		if(self->priv->current_serial == NULL || g_strcmp0(self->priv->current_serial,ad->serial) == 0){
			aiter = iter;
		}
		l=l->next;
		g_free(dn);
	}

	gtk_combo_box_set_active_iter (GTK_COMBO_BOX(self->priv->devices_box),&aiter);
}

void
on_btn_refresh_clicked(GtkWidget *widget,WindowWrapper *self)
{
	self->priv->kill_before_device_list  = TRUE;
	window_wrapper_load_devices(self);
	gtk_widget_set_sensitive (self->priv->btn_refresh,FALSE);
	gtk_widget_set_sensitive (self->priv->btn_install,FALSE);
}

void on_install_callback(GApkObject *apk,gboolean isOk,const gchar *msg,WindowWrapper *self)
{
	gtk_window_set_title (GTK_WINDOW(self->priv->message_dialog),isOk?_("Success"):_("Failed"));
	gtk_label_set_label (GTK_LABEL(self->priv->msg_label),msg);
	gtk_widget_set_sensitive (GTK_WIDGET(self->priv->btn_dialog),TRUE);
	gtk_widget_set_visible (GTK_WIDGET(self->priv->spinner),FALSE);
	gtk_spinner_stop (GTK_SPINNER(self->priv->spinner));
	self->priv->isWorking = FALSE;
}

void
on_btn_install_clicked(GtkWidget *widget,WindowWrapper *self)
{

	GtkTreeIter iter;
	if(gtk_combo_box_get_active_iter (GTK_COMBO_BOX(self->priv->devices_box),&iter)){
		gchar *serial = NULL;
		gtk_tree_model_get(GTK_TREE_MODEL(self->priv->device_list),
		                   &iter,
						   1,&serial,
		                   -1);
		gtk_widget_set_sensitive (GTK_WIDGET(self->priv->btn_dialog),FALSE);
		gtk_widget_set_visible (GTK_WIDGET(self->priv->spinner),TRUE);
		gtk_spinner_start (GTK_SPINNER(self->priv->spinner));
		gtk_window_present (GTK_WINDOW(self->priv->message_dialog));

		gtk_label_set_label (GTK_LABEL(self->priv->msg_label),_("Installing ..."));

		self->priv->isWorking = TRUE;
		g_apk_object_install(self->priv->apk,serial,on_install_callback,self);

		gchar *title = g_strdup_printf(_("Install %s"),g_apk_object_appname(self->priv->apk));
		gtk_window_set_title (GTK_WINDOW(self->priv->message_dialog),title);
		g_free(title);
	}
}

void
on_app_box_drag_data_received(GtkWidget        *widget,
               GdkDragContext   *context,
               gint              x,
               gint              y,
               GtkSelectionData *data,
               guint             info,
               guint             time,
               WindowWrapper *self)
{
//	g_warning("on_app_box_drag_data_received");
	gchar **vv = g_uri_list_extract_uris ((char*) gtk_selection_data_get_data (data));
	if (vv == NULL) {
		GtkWidget *d;

		d = gtk_message_dialog_new (GTK_WINDOW (self->priv->window),
					   GTK_DIALOG_MODAL,
					   GTK_MESSAGE_ERROR,
		               GTK_BUTTONS_CLOSE,
					   "Could not perform the operation",
					   NULL);
		gtk_dialog_run (GTK_DIALOG (d));
		gtk_widget_destroy(d);

 		return;
	}

	int i=0;
	gchar *f = NULL;
	if(!g_apk_object_is_opened(self->priv->apk)){
		f  = g_filename_from_uri(vv[i],NULL,NULL);
		if(g_str_has_suffix (f,".apk") || g_str_has_suffix (f,".APK")){
			g_apk_object_open(self->priv->apk,f);
			i++;
		}
		g_free(f);
	}

	for(;vv[i];i++){
		f  = g_filename_from_uri(vv[i],NULL,NULL);
		if(g_file_test (f,G_FILE_TEST_EXISTS) && (g_str_has_suffix (f,".apk") || g_str_has_suffix (f,".APK"))){
			window_wrapper_new_window(self->priv->thisApp,f);
		}
		g_free(f);
	}
	g_strfreev (vv);

}

gboolean
on_app_box_drag_drop (GtkWidget      *widget,
               GdkDragContext *context,
               gint            x,
               gint            y,
               guint           time,
               WindowWrapper *self)
{
///	g_warning("on_app_box_drag_drop");
	gtk_drag_finish (context,TRUE,FALSE,gtk_get_current_event_time());
	return FALSE;
}

gboolean
on_app_box_drag_motion(GtkWidget *widget,
                       GdkDragContext *context,
                       gint x, gint y, guint t,
    				   WindowWrapper *self)
{
//	g_warning("on_app_box_drag_motion");
	///gtk_drag_finish (context,FALSE,FALSE,gtk_get_current_event_time());
	return FALSE;
}

void
on_btn_cancel_clicked(GtkWidget *widget,WindowWrapper *self)
{
	gtk_widget_destroy (GTK_WIDGET (self->priv->window));
}

void
on_btn_dialog_clicked(GtkWidget *widget,WindowWrapper *self)
{
	gtk_widget_hide (GTK_WIDGET(self->priv->message_dialog));
}

void
on_devices_box_changed(GtkWidget *widget,WindowWrapper *self)
{
	g_free(self->priv->current_serial);
	GtkTreeIter iter;
	self->priv->current_serial = NULL;
	if(gtk_combo_box_get_active_iter (GTK_COMBO_BOX(self->priv->devices_box),&iter))
	gtk_tree_model_get(GTK_TREE_MODEL(self->priv->device_list),&iter,1,&self->priv->current_serial,-1);
}

static gboolean
window_wrapper_on_delete_event(WindowWrapper *self,GdkEvent  *event,GtkWidget *widget)
{
	return self->priv->isWorking;
}

/* Create a new window loading a file */
void
window_wrapper_new_window (GApplication *app,
                           const gchar  *file)
{
	GtkWidget *window;

	GtkBuilder *builder;
	GError* error = NULL;
	/* Load UI from file */
	builder = gtk_builder_new ();
	if (!gtk_builder_add_from_file (builder, UI_FILE, &error))
	{
		g_critical ("Couldn't load builder file: %s", error->message);
		g_error_free (error);
	}

	/* Get the window object from the ui file */
	window = GTK_WIDGET (gtk_builder_get_object (builder, TOP_WINDOW));
    if (!window)
    {
		g_critical ("Widget \"%s\" is missing in file %s.",
				TOP_WINDOW,
				UI_FILE);
	}

	WindowWrapper *ww = window_wrapper_new();
	ww->priv->builder = builder;
	ww->priv->window = GTK_WINDOW(window);
	ww->priv->thisApp = app;
	window_wrapper_init_widgets(ww);
	

		/* Auto-connect signal handlers */
	gtk_builder_connect_signals (builder, ww);

	gtk_window_set_application (GTK_WINDOW (window), GTK_APPLICATION (app));
	if (file != NULL)
	{
		g_apk_object_open(ww->priv->apk,file);
	}else{
		gtk_label_set_label (GTK_LABEL(ww->priv->app_label),_("Drag an apk file to here"));
	}
	window_wrapper_load_devices(ww);
	g_signal_connect_swapped(window,"destroy",G_CALLBACK(g_object_unref),ww);
	g_signal_connect_swapped(window,"delete-event",G_CALLBACK(window_wrapper_on_delete_event),ww);
	gtk_widget_show_all (GTK_WIDGET (window));
}

